package com.uci.scheduleshare;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.util.List;

import com.bump.api.BumpAPIIntents;
import com.bump.api.IBumpAPI;
import com.uci.scheduleshare.adapters.*;
import com.uci.scheduleshare.calendar.*;
import com.uci.scheduleshare.calendardb.*;
import com.viewpagerindicator.*;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.StrictMode;
import android.provider.Settings;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;


/**
 * CS 190 Spring 2012
 * ScheduleShareActivity.java
 * The main activity for the application. 
 * Creates all the adapters, database access objects, and Bump API
 * 
 * @author Patrick Hsu, Lauren Ko, Pomi Park
 *
 */
public class ScheduleShareActivity extends Activity {
	
	private static final int SETTINGS_CODE = 0;
	
	private IBumpAPI api;
	
	// Database Access Objects
	private CalendarDBAdapter dbAdapter;
	private CalendarDatabase calendarDB;
	private DBApplication dbApp;
	
	// User's default calendar
	private String defaultCalendarID;
	
	private List<Contact> contacts;
	private List<String> activities;
	
	private SharedPreferences myPrefs;
	
	// Adapters
	private ContactsAdapter contactsAdapter;
	private ViewPagerAdapter viewPagerAdapter;
	private RecentActivityAdapter activityAdapter;
	
	// Data to be sent through Bump
	private Contact mContact;
	
	// UI colors
	private int footerColor = 0xFF37b415;
	private int titleBackgroundColor = 0xFF3c3c3c;
	private final int textColor = 0xFF3c3c3c;
	
	private ImageView bumpLogo;
	
	List<Event> myEvents;
	
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
		setContentView(R.layout.main);
		getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.custom_title_bar);
	    // Preferences
	    myPrefs = getSharedPreferences("myPrefs", MODE_WORLD_READABLE);
	    defaultCalendarID = myPrefs.getString("default_calendar", "1");
	    
	    // Check for internet & location services
	    checkLocationAndGPS();
	    bumpLogo = (ImageView)findViewById(R.id.bumplogo);
	    bumpLogo.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				checkLocationAndGPS();
			}
		});
	    
		// Database object creation
		dbApp = (DBApplication)getApplication();
		if(dbApp.getDbAdapter() == null) {
			dbAdapter = new CalendarDBAdapter(this);
			dbApp.setDbAdapter(dbAdapter);
		} else {
			dbAdapter = dbApp.getDbAdapter();
		}
		calendarDB = new CalendarDatabase(this, CalendarDatabase.DB_NAME, null, CalendarDatabase.DB_VERSION);
		
		// Create contact for self
		mContact = dbAdapter.createContact(defaultCalendarID);
		int myColor = myPrefs.getInt("color", 0x800000FF);
		mContact.setColor(myColor);
		
		// Populate the contacts and activities lists
		contacts = calendarDB.getAllContacts();
		contacts.add(0, mContact);
	    activities = calendarDB.getRecentActivity();
	    
	    // Adapters
		contactsAdapter = new ContactsAdapter(contacts, this, calendarDB, myPrefs);
		activityAdapter = new RecentActivityAdapter(this, activities);
		viewPagerAdapter = new ViewPagerAdapter(this, contacts, activities, contactsAdapter, activityAdapter, calendarDB);
		ViewPager pager = (ViewPager) findViewById(R.id.viewpager);
		TitlePageIndicator indicator = (TitlePageIndicator) findViewById(R.id.indicator);
		indicator.setFooterColor(footerColor);
		indicator.setBackgroundColor(titleBackgroundColor);
		indicator.setSelectedBold(true);
		pager.setAdapter(viewPagerAdapter);
		indicator.setViewPager(pager);
		
		// For allowing Bump network access 
		StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
		StrictMode.setThreadPolicy(policy); 
		
		// Bump stuff
        bindService(new Intent(IBumpAPI.class.getName()),
                connection, Context.BIND_AUTO_CREATE);
	    Log.i("BumpTest", "boot");
	
	    IntentFilter filter = new IntentFilter();
	    filter.addAction(BumpAPIIntents.CHANNEL_CONFIRMED);
	    filter.addAction(BumpAPIIntents.DATA_RECEIVED);
	    filter.addAction(BumpAPIIntents.NOT_MATCHED);
	    filter.addAction(BumpAPIIntents.MATCHED);
	    filter.addAction(BumpAPIIntents.CONNECTED);
	    registerReceiver(receiver, filter);
	  
	}
	
	// MENU BUTTON //
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.add(0, SETTINGS_CODE, 0, "Settings"); // Adding a "Settings" option
		return super.onCreateOptionsMenu(menu);
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		if(item.getItemId() == SETTINGS_CODE) {
			// Start the SettingsActivity class
			startActivityForResult(new Intent(this, SettingsActivity.class), SETTINGS_CODE);
		}
		return super.onOptionsItemSelected(item);
	};
	
	@Override
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);
		if(requestCode == SETTINGS_CODE && resultCode == Activity.RESULT_OK) {
			// Once preferences have changed, set the new default calendar id
			String newDefaultCalendarID = data.getStringExtra("defaultCalendarID");
			defaultCalendarID = newDefaultCalendarID;
			Contact myNewContact = dbAdapter.createContact(defaultCalendarID);
			mContact = myNewContact;
			int myColor = myPrefs.getInt("color", 0x800000FF);
			mContact.setColor(myColor);
			// Remove the old contact from the contacts list and add the new one
			for(int i = 0; i < contacts.size(); i++) {
				if(contacts.get(i).isMe()) {
					contacts.remove(i);
					contacts.add(i, mContact);
					contactsAdapter.notifyDataSetChanged();
				}
			}
		}
	}
	
	
	// BUMP //
	
	/**
	 * Create a new ServiceConnection to connect to the Bump servers
	 */
	 private final ServiceConnection connection = new ServiceConnection() {
	        @Override
	        public void onServiceConnected(ComponentName className, IBinder binder) {
	            Log.i("ScheduleShare", "onServiceConnected");
	            api = IBumpAPI.Stub.asInterface(binder);
	            try {
	                api.configure("18821610fbf04579814d05bb287e2856",
	                              "ScheduleShare User");
	            } catch (RemoteException e) {
	                Log.w("ScheduleShare", e);
	            }
	            Log.d("ScheduleShare", "Service connected");
	        }

	        @Override
	        public void onServiceDisconnected(ComponentName className) {
	            Log.d("ScheduleShare", "Service disconnected");
	        }
	    };
	    
	    /**
	     * Create a BroadcastReceiver - for sending and receiving Bump data
	     */
	    private final BroadcastReceiver receiver = new BroadcastReceiver() {
	        @Override
	        public void onReceive(Context context, Intent intent) {
	            final String action = intent.getAction();
	            try {
	                if (action.equals(BumpAPIIntents.DATA_RECEIVED)) {
	                    Log.i("ScheduleShare", "Received data from: " + api.userIDForChannelID(intent.getLongExtra("channelID", 0))); 
	                    ByteArrayInputStream bis = new ByteArrayInputStream(intent.getByteArrayExtra("data"));
	                    try {
	                    	ObjectInput in = new ObjectInputStream(bis);
	                    	try {
								Contact receiveContact = (Contact) in.readObject();
								
								// Add received contact to the database
								receiveContact.setID(calendarDB.addContact(receiveContact));
								contacts.add(receiveContact);
								// Add a new note to Recent Activity
								activities.add(calendarDB.addActivity(receiveContact.getName(), 
										receiveContact.getCalendarName(), 0));
								// notify adapters of changes
								contactsAdapter.notifyDataSetChanged();
								activityAdapter.notifyDataSetChanged();
								
							} catch (ClassNotFoundException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							bis.close();
							in.close();
						} catch (StreamCorruptedException e) {
							Log.d("StreamCorruptedException", e.toString());
						} catch (IOException e) {
							Log.d("IOException", e.toString());
						}

	                } else if (action.equals(BumpAPIIntents.MATCHED)) {
	                    long channelID = intent.getLongExtra("proposedChannelID", 0); 
	                    Log.i("ScheduleShare", "Matched with: " + api.userIDForChannelID(channelID));
	                    api.confirm(channelID, true);
	                    Log.i("ScheduleShare", "Confirm sent");
	                    // Successfully matched
	                } else if (action.equals(BumpAPIIntents.CHANNEL_CONFIRMED)) {
	                    long channelID = intent.getLongExtra("channelID", 0);
	                    Log.i("ScheduleShare", "Channel confirmed with " + api.userIDForChannelID(channelID));
	                    ByteArrayOutputStream bo = new ByteArrayOutputStream();
	                    ObjectOutput out;
						try {
							// Channel confirmed, write object out to byte array
							out = new ObjectOutputStream(bo);
		                    out.writeObject(mContact);
						} catch (IOException e) {
							Log.d("IOException", e.toString());
						}
	                    byte[] bytes = bo.toByteArray();
	                    api.send(channelID, bytes);
	                    
	                } else if (action.equals(BumpAPIIntents.NOT_MATCHED)) {
	                    Log.i("ScheduleShare", "Not matched.");
	                } else if (action.equals(BumpAPIIntents.CONNECTED)) {
	                    Log.i("ScheduleShare", "Connected to Bump...");
	                    api.enableBumping();
	                }
	            } catch (RemoteException e) {}
	        } 
	    };

	    @Override
	    public void onConfigurationChanged(Configuration newConfig) {
	      super.onConfigurationChanged(newConfig);
	    }

	    public void onStart() {
	        Log.i("ScheduleShare", "onStart");
	        super.onStart();
	     }
	     
	     public void onRestart() {
	        Log.i("ScheduleShare", "onRestart");
	        super.onRestart();
	     }

	     public void onResume() {
	        Log.i("ScheduleShare", "onResume");
	        super.onResume();
	     }

	     public void onPause() {
	        Log.i("ScheduleShare", "onPause");
	        super.onPause();
	     }

	     public void onStop() {
	        Log.i("ScheduleShare", "onStop");
	        super.onStop();
	     }

	     public void onDestroy() {
	        Log.i("ScheduleShare", "onDestroy");
	        unbindService(connection);
	       if(receiver != null){ unregisterReceiver(receiver);}
	        if(calendarDB != null) {
	        	calendarDB.close();
	        }
	        super.onDestroy();
	     }
	     
	     public void checkLocationAndGPS() {
	 	    String provider = Settings.Secure.getString(getContentResolver(), Settings.Secure.LOCATION_PROVIDERS_ALLOWED);    
	 	   String toastText = "";
	 	    if(!provider.contains("gps") || !provider.contains("network")) {
			    if(!provider.contains("gps") && provider.contains("network")) {
			    	toastText = "GPS not enabled. Please enable GPS.";
			    } else if (!provider.contains("network") && provider.contains("gps")) {
			    	toastText = "Network not enabled. Please enable WiFi or 3G.";
			    } else if (!provider.contains("gps") && !provider.contains("network")) {
			    	toastText = "Network and GPS not enabled. Please enable network and GPS";
			    }

		    } else {
		    	toastText = "GPS and Network enabled. Bump now!";
		    }
		    Toast toast = Toast.makeText(this, toastText, Toast.LENGTH_LONG);
		    toast.show();
	     }

}
